#include "bsp_uart_dma.h"
#include "cbb_init.h"
#include "at32f403a_407.h"

// 初始化串口1
void uart1_dma_init(void){

    // 时钟
    crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
    crm_periph_clock_enable(CRM_USART1_PERIPH_CLOCK, TRUE);
   
    // tx
    gpio_init_type GPIO_InitStructure;
    GPIO_InitStructure.gpio_pins = GPIO_PINS_9;
    GPIO_InitStructure.gpio_mode = GPIO_MODE_MUX;
    GPIO_InitStructure.gpio_pull = GPIO_PULL_NONE;
    GPIO_InitStructure.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
    GPIO_InitStructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE;
    gpio_init(GPIOA, &GPIO_InitStructure);

    // rx
    GPIO_InitStructure.gpio_pins = GPIO_PINS_10;
    GPIO_InitStructure.gpio_mode = GPIO_MODE_INPUT;
    GPIO_InitStructure.gpio_pull = GPIO_PULL_NONE;
    gpio_init(GPIOA, &GPIO_InitStructure);

    // DMA clock
    crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);
    
    // tx dma
    dma_init_type dma_init_struct;
    dma_init_struct.peripheral_base_addr = (uint32_t)&USART1->dt;
    dma_init_struct.direction = DMA_DIR_MEMORY_TO_PERIPHERAL;
    dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
    dma_init_struct.memory_inc_enable = TRUE;
    dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
    dma_init_struct.peripheral_inc_enable = FALSE;
    dma_init_struct.priority = DMA_PRIORITY_LOW;
    dma_init_struct.loop_mode_enable = FALSE;
    dma_init(DMA1_CHANNEL4, &dma_init_struct);
    dma_flexible_config(DMA1, FLEX_CHANNEL4, DMA_FLEXIBLE_UART1_TX);

    // rx dma
    dma_default_para_init(&dma_init_struct);
    dma_init_struct.peripheral_base_addr = (uint32_t)&USART1->dt;
    dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
    dma_init_struct.memory_inc_enable = TRUE;
    dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
    dma_init_struct.peripheral_inc_enable = FALSE;
    dma_init_struct.priority = DMA_PRIORITY_LOW;
    dma_init_struct.loop_mode_enable = TRUE;
    dma_init(DMA1_CHANNEL5, &dma_init_struct);
    dma_flexible_config(DMA1, FLEX_CHANNEL5, DMA_FLEXIBLE_UART1_RX);

    // USART1
    usart_init(USART1, 921600, USART_DATA_8BITS, USART_STOP_1_BIT);
    usart_parity_selection_config(USART1, USART_PARITY_NONE);
    usart_hardware_flow_control_set(USART1, USART_HARDWARE_FLOW_NONE);
    
    // 使能发送，接收
    usart_transmitter_enable(USART1, TRUE);
    usart_receiver_enable(USART1, TRUE);

    // DMA
    usart_dma_receiver_enable(USART1, TRUE);
    usart_dma_transmitter_enable(USART1, TRUE);

    // 使能DMA通道
    dma_channel_enable(DMA1_CHANNEL5, FALSE);
    dma_channel_enable(DMA1_CHANNEL4, FALSE);

    // 开启串口
    usart_enable(USART1, TRUE);

}
INIT_PORT_BSP(uart1_dma_init);

uint8_t uart1_dma_transmit(uint8_t* pu8Data, uint32_t u32Len){
    
    // 关闭dma设置参数
    dma_channel_enable(DMA1_CHANNEL4, FALSE);
    usart_dma_transmitter_enable(USART1, FALSE);
    
    // 设置dma地址
    DMA1_CHANNEL4->maddr = (uint32_t)pu8Data;
    
    // 设置dma传输长度
    DMA1_CHANNEL4->dtcnt = u32Len;

    // 开启dma
    usart_dma_transmitter_enable(USART1, TRUE);
    dma_channel_enable(DMA1_CHANNEL4, TRUE);

    // 等待发送结束
    while(dma_flag_get(DMA1_FDT4_FLAG) == RESET);
    dma_flag_clear(DMA1_FDT4_FLAG);

    // 发送成功
    return 0;
}

uint32_t uart1_dma_receive(uint8_t* pu8Data, uint32_t u32Len){

    // check if dma is already enabled
    if(!(DMA1_CHANNEL5->ctrl & 0x01)){
        // disabled dma to set parameters
        dma_channel_enable(DMA1_CHANNEL5, FALSE);
        usart_dma_receiver_enable(USART1, FALSE);
    
        // set dma memory address
        DMA1_CHANNEL5->maddr = (uint32_t)pu8Data;
    
        // set dma transfer length
        DMA1_CHANNEL5->dtcnt = u32Len;
    
        // enabled dma to receive data
        usart_dma_receiver_enable(USART1, TRUE);
        dma_channel_enable(DMA1_CHANNEL5, TRUE);
    }

    // 是否有空闲标志
    if(!USART1->sts_bit.idlef) return 0;

    // 清空标志
    USART1->sts;
    USART1->dt;

    // 返回数据
    return dma_data_number_get(DMA1_CHANNEL5);

}


// debug使用的打印函数
uint8_t uart1_printf(uint8_t u8Data){
    usart_data_transmit(USART1, u8Data);
    while(USART1->sts_bit.tdbe == RESET);
    return 0;
}

int __io_putchar(int ch){
    uart1_printf((uint8_t)ch);
    return ch;
}
